home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / gcc / ixemulsrc.lha / ixemul-41.4 / library / lseek.c < prev    next >
C/C++ Source or Header  |  1995-05-28  |  7KB  |  265 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  lseek.c,v 1.1.1.1 1994/04/04 04:30:29 amiga Exp
  20.  *
  21.  *  lseek.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:29  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  26.  *  Initial revision
  27.  *
  28.  */
  29.  
  30. #define KERNEL
  31. #include "ixemul.h"
  32. #include "kprintf.h"
  33.  
  34. static inline int
  35. __extend_file (struct file *f, int add_to_eof, int *err)
  36. {
  37.   int res = 0;
  38.   int buf_size, written;
  39.   char *buf;
  40.  
  41.   /* now you know perhaps, that starting with OS2.0 there's a packet that
  42.      sets the size of a file (used in [f]truncate()). Too bad, that the 
  43.      following statement from the autodocs render this packet useless... :
  44.  
  45.      `` Do NOT count on any specific values to be in the extended area. ''
  46.    
  47.      Since **IX requires the new area to be zero'd, we can just as well
  48.      write zeros without the use of the new packet ;-(( */
  49.   
  50.       
  51.   buf_size = add_to_eof > 32*1024 ? 32*1024 : add_to_eof;
  52.   while (! (buf = (char *) kmalloc (buf_size)) && buf_size)
  53.     buf_size >>= 1;
  54.   if (buf)
  55.     {
  56.       bzero (buf, buf_size);
  57.  
  58.       for (written = 0; written < add_to_eof; )
  59.         {
  60.       SendPacket3(f,__rwport,ACTION_WRITE,f->f_fh->fh_Arg1,(long)buf,buf_size);
  61.       __wait_packet(&f->f_sp);
  62.       res = LastResult (f);
  63.           if (res < 0)
  64.             {
  65.               *err = LastError (f);
  66.               break;
  67.             }
  68.           written += res;
  69.           buf_size = add_to_eof - written > buf_size ? 
  70.                buf_size : add_to_eof - written;
  71.     }
  72.       kfree (buf);
  73.     }
  74.   else
  75.     {
  76.       *err = ENOMEM;
  77.       res = -1;
  78.     }
  79.  
  80.   if (res >= 0)
  81.     {
  82.       SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  83.      __wait_packet (&f->f_sp);
  84.       LastError(f) = 0;
  85.       SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  86.      __wait_packet (&f->f_sp);
  87.      res = LastError (f) ? -1 : LastResult (f);
  88.      *err = __ioerr_to_errno (LastError (f));
  89.    }
  90.  
  91.   return res;
  92. }
  93.  
  94.  
  95. off_t
  96. lseek (int fd, off_t off, int dir)
  97. {
  98.   struct file *f = u.u_ofile[fd];
  99.   int omask;
  100.   int err, res;
  101.   int previous_pos, shouldbe_pos;
  102.  
  103.   /* if this is an open fd */
  104.   if (fd >= 0 && fd < NOFILE && f)
  105.     {
  106.       if (f->f_type == DTYPE_FILE)
  107.     {
  108.           if (HANDLER_NIL(f))
  109.         {
  110.           errno = ESPIPE;
  111.           KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  112.           return -1;
  113.         }
  114.  
  115.       omask = syscall (SYS_sigsetmask, ~0);
  116.       __get_file (f);
  117.       __wait_packet(&f->f_sp);
  118.  
  119.       /* there's a subtle difference between Unix lseek() and AmigaDOS
  120.        * Seek(): lseek() returns the *current* position of the `pointer',
  121.        * Seek() returns the *previous* position. So in some cases, we
  122.        * have to do another Seek() to find out where we are.
  123.        * Thanks Mike for pointing me at this! */
  124.  
  125.       switch (dir)
  126.         {
  127.         case SEEK_SET:
  128.           /* previous doesn't matter, don't need to seek */
  129.           previous_pos = 0;
  130.           break;
  131.  
  132.         case SEEK_CUR:
  133.           /* first find out current position */
  134.           LastError(f) = 0;
  135.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  136.           __wait_packet (&f->f_sp);
  137.           if (LastError(f) || LastResult(f) < 0)
  138.             {
  139.               err = __ioerr_to_errno(LastError(f));
  140.               previous_pos = -1;
  141.             }
  142.           else
  143.             previous_pos = LastResult(f);
  144.           break;
  145.           
  146.         case SEEK_END:
  147.           /* first find out end position (have to do twice.. argl) */
  148.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  149.           __wait_packet (&f->f_sp);
  150.           LastError(f) = 0;
  151.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  152.           __wait_packet (&f->f_sp);
  153.           if (LastError(f) || LastResult(f) < 0)
  154.             {
  155.               err = __ioerr_to_errno(LastError(f));
  156.               previous_pos = -1;
  157.             }
  158.           else
  159.             previous_pos = LastResult(f);
  160.           break;
  161.         }
  162.       
  163.       shouldbe_pos = previous_pos + off;
  164.       if (shouldbe_pos < 0)
  165.         {
  166.           /* that way we make sure that invalid seek errors later result
  167.              from seeking past eof, so we can enlarge the file */
  168.  
  169.           err = EINVAL;
  170.           res = -1;
  171.         }
  172.       else if (previous_pos >= 0)
  173.         {
  174.           /* reset the error field */
  175.           LastError(f) = 0;
  176.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,off,dir-1);
  177.           __wait_packet(&f->f_sp);
  178.  
  179.           if (LastError (f) == ERROR_SEEK_ERROR)
  180.             {
  181.               /* in this case, assume the user wanted to seek past eof.
  182.                  Thus get the current eof position, so that we can
  183.                  tell __extend_file how much to enlarge the file */
  184.           
  185.           LastError(f) = 0;
  186.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  187.           __wait_packet (&f->f_sp);
  188.             }
  189.       
  190.           if (LastError (f) || LastResult (f) < 0)
  191.             {
  192.               err = __ioerr_to_errno(LastError(f));
  193.               res = -1;
  194.             }
  195.           else
  196.             {
  197.               err = 0;
  198.  
  199.               if (previous_pos != shouldbe_pos)
  200.             {
  201.               SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  202.               __wait_packet (&f->f_sp);
  203.               if (LastError (f) || LastResult(f) < 0)
  204.                 {
  205.                       err = __ioerr_to_errno(LastError(f));
  206.                       res = -1;
  207.                     }
  208.               else
  209.                     res = LastResult(f);
  210.  
  211.                   if (res >= 0 && res < shouldbe_pos && (f->f_flags & FWRITE))
  212.                     {
  213.                       /* extend the file... */
  214.                   res = __extend_file (f, shouldbe_pos - res, &err);
  215.                 }
  216.             }
  217.           else
  218.             res = shouldbe_pos;
  219.             }
  220.         }
  221.       else
  222.         res = -1;
  223.       
  224.       LastResult(f) = 0;
  225.       __release_file (f);
  226.       syscall (SYS_sigsetmask, omask);
  227.       errno = err;
  228.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  229.       return res;
  230.     }
  231.       else if (f->f_type == DTYPE_MEM)
  232.     {
  233.       int real_off;
  234.       int old_off;
  235.  
  236.       omask = syscall (SYS_sigsetmask, ~0);
  237.       __get_file (f);
  238.       old_off = f->f_mf.mf_offset;
  239.       
  240.       real_off = (dir == L_SET ? off : 
  241.               (dir == L_INCR ? 
  242.                old_off + off : f->f_stb.st_size + off));
  243.       if (real_off < 0) real_off = 0;
  244.       else if (real_off > f->f_stb.st_size) real_off = f->f_stb.st_size;
  245.       f->f_mf.mf_offset = real_off;
  246.       __release_file (f);
  247.       syscall (SYS_sigsetmask, omask);
  248.       return old_off;
  249.     }
  250.       else
  251.     {
  252.       errno = ESPIPE;
  253.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  254.     }
  255.     }
  256.   else
  257.     {
  258.       errno = EBADF;
  259.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  260.     }
  261.  
  262.   return -1;
  263. }
  264.  
  265.